using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider))]
public class ShadowPlatformObject : MonoBehaviour
{
    public Light lightSource;
    public Transform[] shadowCaster;
    public LayerMask wallLayer;

    [Tooltip("生成的物理平台的厚度")] public float platformThickness = 0.2f;
    private Mesh _platformMesh;
    private MeshCollider _platformMeshCollider;
    // Start is called before the first frame update
    void Start()
    {
        _platformMesh=new Mesh{name ="Shadow Platform Mesh"};
        GetComponent<MeshFilter>().mesh = _platformMesh;
        _platformMeshCollider=GetComponent<MeshCollider>();
        //将MeshCollider设置为凸体，这样他才能成为一个实心物体
        _platformMeshCollider.convex=true;
        //正常游戏时禁用构建出来的渲染
        GetComponent<MeshRenderer>().enabled=false;
    }

    // Update is called once per frame
    void Update()
    {
        for (int i = 0; i < shadowCaster.Length; i++)
        {
            UpdateShadowPlatform(shadowCaster[i]);
        }
    }

    // ReSharper disable Unity.PerformanceAnalysis
    private void UpdateShadowPlatform(Transform cast)
    {
        if (!lightSource||!cast) return;
        Mesh casterMesh=cast.GetComponent<MeshFilter>().mesh;
        if(casterMesh==null) return;
        Vector3[] vertices=casterMesh.vertices;
        //投影在墙上的正面顶点
        List<Vector3> baseVerticesWorld=new List<Vector3>();
        //挤出方向
        Vector3 extrusionDirection=Vector3.zero;
        RaycastHit hitInfo;
        var lightposition=lightSource.transform.position;
        foreach (var vertex in vertices)
        {
            Vector3 worldVertex = cast.TransformPoint(vertex);
            Vector3 dirFromLight=(worldVertex-lightposition).normalized;
            if (Physics.Raycast(lightposition, dirFromLight, out hitInfo, 100f, wallLayer))
            {
                baseVerticesWorld.Add(hitInfo.point);
                if (extrusionDirection == Vector3.zero)
                    extrusionDirection = hitInfo.normal;
            }
        }
        if (baseVerticesWorld.Count < 3)
        {
            _platformMesh.Clear();
            return;
        }
        int numBaseVertices=baseVerticesWorld.Count;
        var allVertices = new Vector3[numBaseVertices * 2];
        //创建所有顶点（基础面和挤压面）
        for (int i = 0; i < numBaseVertices; i++)
        {
            //将世界坐标转换为此对象的局部坐标
            //基础面顶点
            allVertices[i]=transform.InverseTransformPoint(baseVerticesWorld[i]);
            allVertices[i+numBaseVertices]=transform.InverseTransformPoint(baseVerticesWorld[i]+extrusionDirection*platformThickness);
        }
        //创建基础面和挤压面的三角形
        int[] baseTriangles = TriangulateConvexPolygon(numBaseVertices, 0);
        int[] extrusTriangles=TriangulateConvexPolygon(numBaseVertices, numBaseVertices);
        System.Array.Reverse(extrusTriangles);
        var triangles = new List<int>();
        triangles.AddRange(baseTriangles);
        triangles.AddRange(extrusTriangles);
        for (int i = 0; i < numBaseVertices; i++)
        {
            int currentFront = i;
            int nextFront = (i+1)%numBaseVertices;
            int currentBack = i+numBaseVertices;
            int nextBack = ((i+1)%numBaseVertices)+numBaseVertices;
            triangles.Add(currentFront);
            triangles.Add(nextBack);
            triangles.Add(nextFront);
            
            triangles.Add(currentFront);
            triangles.Add(currentBack);
            triangles.Add(nextBack);
        }
        _platformMesh.Clear();
        _platformMesh.vertices=allVertices;
        _platformMesh.triangles=triangles.ToArray();
        _platformMesh.RecalculateNormals();
        _platformMesh.RecalculateBounds();
        _platformMeshCollider.sharedMesh = _platformMesh;
    }

    private int[] TriangulateConvexPolygon(int vertexCount, int offset)
    {
        List<int> triangles=new List<int>();
        if(vertexCount<3) return triangles.ToArray();
        for (int i = 1; i < vertexCount - 1; i++)
        {
            triangles.Add(offset);
            triangles.Add(offset+i);
            triangles.Add(offset+i+1);
        }
        return triangles.ToArray();
    }
}
